package yl.hs.bmipfull.service.production.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yl.hs.bmipfull.daos.finance.IReceivePaymentRecordDao;
import yl.hs.bmipfull.daos.laboratory.IProductOverageDao;
import yl.hs.bmipfull.daos.production.IProductShipOrderDao;
import yl.hs.bmipfull.daos.production.IProductionDispatchLogDao;
import yl.hs.bmipfull.daos.production.IProductionTaskDao;
import yl.hs.bmipfull.daos.production.ITransTaskDao;
import yl.hs.bmipfull.daos.salemanage.IContractControlInfoDao;
import yl.hs.bmipfull.daos.vehiclemanage.ITruckInfoDao;
import yl.hs.bmipfull.pojo.laboratory.ProductOverageEntity;
import yl.hs.bmipfull.pojo.production.ProductShipOrderEntity;
import yl.hs.bmipfull.pojo.production.ProductionDispatchLogEntity;
import yl.hs.bmipfull.pojo.production.ProductionTaskEntity;
import yl.hs.bmipfull.pojo.production.TransTaskEntity;
import yl.hs.bmipfull.pojo.system.UserInfoEntity;
import yl.hs.bmipfull.pojo.vehiclemanage.TruckInfoEntity;
import yl.hs.bmipfull.service.finance.IContractAccountService;
import yl.hs.bmipfull.service.production.ITransTaskService;
import yl.hs.bmipfull.utils.CK;
import yl.hs.bmipfull.utils.DataState;
import yl.hs.bmipfull.utils.HsApp;
import yl.hs.bmipfull.utils.Tl;
import yl.hs.bmipfull.utils.datastate.ActionType;
import yl.hs.bmipfull.utils.datastate.MsgType;
import yl.hs.bmipfull.utils.datastate.ShipControlState;
import yl.hs.bmipfull.utils.datastate.TruckState;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.PageResult;
import yl.hs.bmipfull.viewmodels.base.StringDecimalModel;
import yl.hs.bmipfull.viewmodels.base.StringIntegerModel;
import yl.hs.bmipfull.viewmodels.host.TransTaskVO;

import java.math.BigDecimal;
import java.util.*;

/**
 * 作用:  运输任务,商砼可以拆为2条派车任务服务层接口实现<br/>
 * 创建时间: 2021年06月19日 09时30分07秒 <br/>
 *
 * @author 谢东
 */
@Service
public class TransTaskServiceImpl extends ProductionBaseService implements ITransTaskService {

    @Autowired
    ITransTaskDao dao;
    @Autowired
    ITruckInfoDao cardao;
    @Autowired
    IProductShipOrderDao shipOrderDao;
    @Autowired
    IProductionDispatchLogDao logDao;
    @Autowired
    IProductOverageDao overageDao;

    @Autowired
    IProductionTaskDao proTaskDao;

    @Autowired
    ITruckInfoDao truckInfoDao;
    @Autowired
    IContractControlInfoDao contractcontroldao;

    IReceivePaymentRecordDao paymentRecordDao;
    @Autowired
    public void setPaymentRecordDao(IReceivePaymentRecordDao paymentRecordDao){
        this.paymentRecordDao = paymentRecordDao;
    }
    @Override
    public List<TransTaskEntity> queryList(PageQuery pageQuery) throws Exception {
        pageQuery.checkSortSides(TransTaskEntity.class);
        return dao.queryPage(pageQuery.getQuery());
    }

    @Override
    public PageResult<TransTaskEntity> queryPage(PageQuery pageQuery, int rowNum, int page) throws Exception {
        pageQuery.checkSortSides(TransTaskEntity.class);
        pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
        pageQuery.getQuery().put("pageSize", rowNum);
        PageResult<TransTaskEntity> result = new PageResult(rowNum);
        result.setRecords(dao.queryCountByCondition(pageQuery.getQuery()));
        result.setPage(page);
        result.setData(dao.queryPage(pageQuery.getQuery()));

        return result;
    }

    @Override
    public PageResult<Map<String, Object>> queryPageByDriver(PageQuery pageQuery, int rowNum, int page) {
        pageQuery.checkSortSides(TransTaskEntity.class);
        pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
        pageQuery.getQuery().put("pageSize", rowNum);
        PageResult<Map<String, Object>> result = new PageResult(rowNum);
        result.setRecords(dao.queryCountByCondition(pageQuery.getQuery()));
        result.setPage(page);
        result.setData(getTranListByTaskSN(pageQuery));
        return result;
    }


    @Override
    public TransTaskEntity findBySn(String sn) {
        return dao.findBySN(sn);
    }

    @Override
    public List<Map<String, Object>> findByTaskSN(String taskSN) {
        Map<String, Object> findMap = new HashMap<>();
        findMap.put("productionTaskSN", taskSN);
        List<TransTaskEntity> transList = dao.queryListByTaskSN(findMap);
        List<Map<String, Object>> transMap = new ArrayList<>();
        if (transList.size() > 0) {
            for (TransTaskEntity entity : transList) {
                var entityMap = entity.toMap();
                ProductionTaskEntity taskEntity = proTaskDao.findBySN(entity.getProductionTaskSN());
                entityMap.put("taskEntity", taskEntity);
                TruckInfoEntity truckEntity = cardao.findBySN(entity.getTruckSN());
                entityMap.put("truckInfo", truckEntity);
                ProductShipOrderEntity shipEntity = shipOrderDao.findBySN(entity.getShipOrderSN());
                entityMap.put("shipEntity", shipEntity);
                ProductOverageEntity overageEntity = overageDao.findBySN(entity.getOverageSN());
                entityMap.put("overageEntity", overageEntity);
                transMap.add(entityMap);
            }
        }
        return transMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveTransTask(Map<String, Object> model, String sn) throws Exception {
        Integer result = 0;
        TransTaskEntity entity = null;
        if (Tl.isEmpty(sn)) {
            //执行保存
            entity = new TransTaskEntity();
            Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            entity.setSn(queryNewSN(TransTaskEntity.class));
            if (entity.getFreightAmount() == null) {
                entity.setFreightAmount(BigDecimal.valueOf(0));
            }
            TruckInfoEntity truckInfoEntity = cardao.findBySN(entity.getTruckSN());
            if (truckInfoEntity != null) {
                entity.setTruckPlate(truckInfoEntity.getTruckPlate());
                entity.setTruckCode(truckInfoEntity.getTruckCode());
            }
            ProductionTaskEntity productionTaskEntity = proTaskDao.findBySN(entity.getProductionTaskSN());
            if (productionTaskEntity != null) {
                entity.setProductSN(productionTaskEntity.getProductSN());
                entity.setProductCateSN(productionTaskEntity.getProductCateSN());
            }
            if (entity.getTransWeight() == null) {
                entity.setTransWeight(BigDecimal.valueOf(0));
            }
            if (entity.getAppendWeight() == null) {
                entity.setAppendWeight(BigDecimal.valueOf(0));
            }
            entity.setDispatchTime(new Date());
            if (entity.getProductionLineSN() == null) {
                entity.setProductionLineSN("");
            }
            if(checkContractControl(productionTaskEntity.getContractSN(),entity.getSaleWeight())==ShipControlState.SHIPMENTOUT){
                return -10;
            }
            result = dao.insertNew(entity);
            //反写余料处理方式
            var overageEntity=overageDao.findBySN(entity.getOverageSN());
            if(overageEntity!=null){
                var ss =  shipOrderDao.findByTruckCodeState(entity.getTruckCode(),(short) 0);
                if(ss.size()>0 && ss!=null){
                    overageEntity.setTransShipOrderSN(ss.get(0).getSn());
                }
                overageEntity.setHandlerType(entity.getOverageHandle());
                overageEntity.setState((short)2);
                overageEntity.setHandlerTime(new Date());
                overageDao.update(overageEntity);
            }
            if (result > 0) {
                //修改车辆状态为等待中
                if (updateTruckState(entity.getTruckSN(),entity.getProductionTaskSN()) > 0) {
                    writeLog(ActionType.CREATE, entity.getSn(), "插入运输任务", Tl.toJson(entity), TransTaskEntity.class);
                }
                saveGS(
                        entity.getSn(),
                        entity.getTruckPlate(),
                        String.join(",",
                                entity.getTruckPlate(),
                                entity.getTruckCode()
                        ),
                        entity,
                        HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                        null
                );
                var driver=cardao.findBySN(entity.getTruckSN());
                var loginUser=HsApp.getCurrent();
                sendMsg(MsgType.System,driver.getDriverSN(),"派车提醒",loginUser.getUserName()+"提醒"+entity.getTruckCode()+"前往生产线等待接料。");
            }

        } else {
            //执行修改
            entity = findBySn(sn);
            Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            if (entity.getFreightAmount() == null) {
                entity.setFreightAmount(BigDecimal.valueOf(0));
            }
            result = dao.update(entity);
            if (result > 0) {
                writeLog(ActionType.UPDATE, sn, "更新运输任务", Tl.toJson(entity), TransTaskEntity.class);
            }
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public Integer updateTruckState(String truckSN,String taskSN) {
        Integer result = 0;
        var car = cardao.findBySN(truckSN);
        car.setState(TruckState.WAITING.code);
        car.setTaskSN(taskSN);
        result = cardao.update(car);
        return result;
    }


    @Override
    public Integer updateTaskSnBySN(String sn, String taskSN) throws Exception {
        TransTaskEntity entity = dao.findBySN(sn);
        entity.setProductionTaskSN(taskSN);
        ProductionTaskEntity taskEntity = proTaskDao.findBySN(taskSN);
        entity.setProductSN(taskEntity.getProductSN());
        var truck = cardao.findBySN(entity.getTruckSN());
        if(truck!=null){
            truck.setTaskSN(taskSN);
            cardao.update(truck);
        }
        return dao.update(entity);
    }

    @Override
    @Transactional
    public Integer delete(String[] sn) {
        Integer result = dao.changeStateBySN(sn, DataState.DELETED.code);
        if (result > 0) {
            writeLog(ActionType.DELETE, sn, TransTaskEntity.class);
        }
        return result;
    }

    @Override
    public List<TransTaskEntity> queryListByTaskCar(String truckCode) {
        return dao.queryListByTaskCar(truckCode);
    }

    @Override
    public List<Map<String, Object>> getTranListByTaskSN(PageQuery pageQuery) {

        List<TransTaskEntity> transList = dao.queryListByTaskSN(pageQuery.getQuery());
        if(pageQuery.getQuery().get("productionTaskSN")==null || "".equals(pageQuery.getQuery().get("productionTaskSN"))){
            if(transList.size()>50){
                transList = transList.subList(0,50);
            }
        }
        List<StringDecimalModel> truckSumNetWeight = new ArrayList<>();
        List<TruckInfoEntity> truckList = new ArrayList<>();
        List<StringDecimalModel> truckAvgTime = new ArrayList<>();
        List<ProductShipOrderEntity> orderList = new ArrayList<>();
        List<ProductOverageEntity> overageList = new ArrayList<>();
        List<ProductionDispatchLogEntity> logList = new ArrayList<>();
        List<UserInfoEntity> userList = new ArrayList<>();
        List<ProductionTaskEntity> pTaskList = new ArrayList<>();
        if(transList.size()>0){
            var taskSN = transList.get(0).getProductionTaskSN();
            truckSumNetWeight.addAll(shipOrderDao.getSumNetWeightByTaskSNAndTruckSN(taskSN));
            truckList.addAll(cardao.queryListBySNList(transList.stream().map(t->t.getTruckSN()).distinct().toList()));
            truckAvgTime.addAll(shipOrderDao.getAVGTransTimeByTaskSNAndTruckSN(taskSN));
            var orderSNList = transList.stream().filter(t->!Tl.isEmpty(t.getShipOrderSN())).map(t->t.getShipOrderSN()).distinct().toList();
            if(orderSNList.size()>0) {
                orderList.addAll(shipOrderDao.queryListByOrderSNList(orderSNList));
            }
            var ovSNList = transList.stream().filter(t->!Tl.isEmpty(t.getOverageSN())).map(t->t.getOverageSN()).distinct().toList();
            if(ovSNList.size()>0) {
                overageList.addAll(overageDao.queryListBySNList(ovSNList));
            }
            logList.addAll(logDao.queryListByMainSN(transList.stream().map(t->t.getSn()).toList(),new short[]{ActionType.CREATE.code,ActionType.UPDATE.code}));
            var userSNList = logList.stream().map(t->t.getUserSN()).distinct().toList();
            if(userSNList.size()>0){
                userList.addAll(userDao.queryByUserSNList(userSNList));
            }
            var pTaskSNList = transList.stream().map(t->t.getProductionTaskSN()).distinct().toList();
            if(pTaskSNList.size()>0) {
                pTaskList.addAll(proTaskDao.queryListBySNList(pTaskSNList));
            }
        }

        List<Map<String, Object>> transMap = new ArrayList<>();

        if (transList.size() > 0) {
            for (TransTaskEntity entity : transList) {
                var entityMap = entity.toMap();
                var pOpt = pTaskList.stream().filter(t->t.getSn().equals(entity.getProductionTaskSN())).findFirst();
                entityMap.put("taskEntity", pOpt.isPresent()?pOpt.get():new ProductionTaskEntity());
                TruckInfoEntity truckEntity=new TruckInfoEntity();
                if(truckList.size()>0){
                    var opt = truckList.stream().filter(t->t.getSn().equals(entity.getTruckSN())).findFirst();
                    if(opt.isPresent()){
                        truckEntity = opt.get();
                    }
                }
                entityMap.put("truckInfo", truckEntity);
                ProductShipOrderEntity shipEntity = new ProductShipOrderEntity();
                if(orderList.size()>0){
                    var opt = orderList.stream().filter(t->t.getSn().equals(entity.getShipOrderSN())).findFirst();
                    if(opt.isPresent()){
                        shipEntity = opt.get();
                    }
                }
                entityMap.put("shipEntity", shipEntity);
                BigDecimal avgTransTime = BigDecimal.ZERO;
                if(truckAvgTime.stream().anyMatch(t->t.getSn().equals(entity.getTruckSN()))){
                    var opt = truckAvgTime.stream().filter(t->t.getSn().equals(entity.getTruckSN())).findFirst();
                    if(opt.isPresent()){
                        avgTransTime = opt.get().getValue();
                    }
                }
                entityMap.put("avgTransTime", avgTransTime);
                //Integer ssCount = shipOrderDao.getCountByTaskSNAndTruckSNAndOrderType(entity.getProductionTaskSN(), entity.getTruckSN());

                entityMap.put("ssCount", entity.getTransType()==2?1:0);
                //Integer tbCount = shipOrderDao.getCountByTaskSNAndTruckSNAndOrderType(entity.getProductionTaskSN(), entity.getTruckSN());
                entityMap.put("tbCount", entity.getTransType()==3?1:0);
                BigDecimal sumNetWeight = BigDecimal.ZERO;
                if(truckSumNetWeight.stream().anyMatch(t->t.getSn().equals(entity.getTruckSN()))){
                    var opt = truckSumNetWeight.stream().filter(t->t.getSn().equals(entity.getTruckSN())).findFirst();
                    if(opt.isPresent()){
                        sumNetWeight = opt.get().getValue();
                    }
                }
                entityMap.put("sumNetWeight", sumNetWeight);
                ProductOverageEntity overageEntity = new ProductOverageEntity();
                if(overageList.size()>0){
                    Optional<ProductOverageEntity> opt = overageList.stream().filter(t -> t.getSn().equals(entity.getOverageSN())).findFirst();
                    if(opt.isPresent()){
                        overageEntity = opt.get();
                    }
                }
                entityMap.put("overageEntity", overageEntity);
                //获取最新修改日志
                var upOpt = logList.stream().filter(t->t.getDataSN().equals(entity.getSn()) && t.getActionType()==ActionType.UPDATE.code).sorted(Comparator.comparing(ProductionDispatchLogEntity::getHandleTime).reversed()).findFirst();
                if (upOpt.isPresent()) {
                    var userOpt= userList.stream().filter(t->t.getSn().equals(upOpt.get().getUserSN())).findFirst();
                    entityMap.put("lastAlertUser", userOpt.isPresent()?userOpt.get().getRealname():null);
                    entityMap.put("lastAlertTime", upOpt.get().getHandleTime());
                } else {
                    entityMap.put("lastAlertUser", null);
                    entityMap.put("lastAlertTime", null);
                }
                //获取创建数据日志
                var createOpt = logList.stream().filter(t->t.getDataSN().equals(entity.getSn()) && t.getActionType()==ActionType.CREATE.code)
                        .sorted(Comparator.comparing(ProductionDispatchLogEntity::getHandleTime).reversed()).findFirst();
                if (createOpt.isPresent()) {
                    var userOpt= userList.stream().filter(t->t.getSn().equals(createOpt.get().getUserSN())).findFirst();
                    entityMap.put("createUser", userOpt.isPresent()?userOpt.get().getRealname():null);
                    entityMap.put("createTime", createOpt.get().getHandleTime());
                } else {
                    entityMap.put("createUser", null);
                    entityMap.put("createTime", null);
                }
                transMap.add(entityMap);
            }
        }
        return transMap;
    }


    @Override
    public Integer updateBySn(short state, String sn) {
        return dao.updateById(state, sn);
    }

    @Override
    public Integer backTransTask(String sn) {
        TransTaskEntity trans = dao.findBySN(sn);
        trans.setState((short) -1);
        Integer result = dao.update(trans);
        if (result > 0) {
            writeLog(ActionType.UPDATE, sn, "撤回运输任务", Tl.toJson(trans), TransTaskEntity.class);
            cardao.updateStateBySN(trans.getTruckSN(), TruckState.LEISURE.code);
        }
        return result;
    }

    @Override
    public List<TransTaskVO> selectByLineSn(String lineSn) {
        List<TransTaskVO> transTasks = new ArrayList<>();
        List<TransTaskEntity> transTaskEntities = dao.selectByLineSn(lineSn);
        transTaskEntities.forEach(t -> {
            TransTaskVO transTaskVO = new TransTaskVO();
            transTaskVO.setSn(t.getSn());
            transTaskVO.setTruckSN(t.getTruckSN());
            TruckInfoEntity truckInfo = truckInfoDao.findBySN(t.getTruckSN());
            if (truckInfo != null){
                transTaskVO.setDriverName(truckInfo.getDriverName());
            }
            transTaskVO.setTruckCode(t.getTruckCode());
            transTaskVO.setTruckPlate(t.getTruckPlate());
            transTaskVO.setDispatchTime(t.getDispatchTime());
            ProductionTaskEntity taskEntity = proTaskDao.findBySN(t.getProductionTaskSN());
            if (taskEntity != null){
                transTaskVO.setCustomName(taskEntity.getCustomName());
                transTaskVO.setProjectName(taskEntity.getProjectName());
                transTaskVO.setPosition(taskEntity.getPosition());
                transTaskVO.setProductName(taskEntity.getProductName());
                transTaskVO.setProductionParam(taskEntity.getProductionParam());
                transTaskVO.setTaskSn(taskEntity.getSn());
                transTaskVO.setProductSpec(taskEntity.getProductSpec());
            }
            transTaskVO.setTransWeight(t.getTransWeight());
            transTaskVO.setSaleWeight(t.getSaleWeight());
            transTaskVO.setAppendWeight(t.getAppendWeight());
            transTaskVO.setState(t.getState());
            transTaskVO.setRemark(t.getRemark());
            transTasks.add(transTaskVO);
        });





        return transTasks;
    }
    @Autowired
    IContractAccountService contractAccountService;
    @Override
    public ShipControlState checkContractControl(String contractSN, BigDecimal netWeight)
    {
        try {
            var contract = contractcontroldao.queryByContractSn(contractSN);
            var result = ShipControlState.ALLOW;
            if(contract!=null && contract.size()>0){

                for (int i = 0; i < contract.size(); i++) {
                    var t = contract.get(i);
                    switch (t.getControlType()){
                        case 1 ->{//天数
                            Date ndate = new Date();
                            var data = (ndate.getTime() - t.getStartTime().getTime()) / (1000 * 60 * 60 * 24);
                            if (data > t.getAlertValue() && data < t.getDisabValue()) {
                                result = ShipControlState.TIMEOUTBJ;
                                result.message = "发货时间到达警告时间";
                            } else if (data > t.getDisabValue()) {
                                result = ShipControlState.TIMEOUT;
                                result.message = "发货时间到达控制时间";
                            }
                        }
                        case 2-> {//金额
                            var price = contractAccountService.getContractBalance(t.getContractSN(),t.getStartTime()).doubleValue();
                            if(t.isControlWay()) {

                                if(price<=t.getAlertValue() && price>t.getDisabValue()){
                                    result = ShipControlState.AMOUNTOUTBJ;
                                    result.message = "发货金额到达警告金额";
                                }else if(price<=t.getDisabValue()){
                                    result = ShipControlState.AMOUNTOUT;
                                    result.message = "发货金额到达控制金额";
                                }
                            }
                            else
                            {
                                var payedAmount =paymentRecordDao.queryContractReceiveAmount(t.getContractSN(),t.getStartTime());
                                var nAmount= new BigDecimal(price).subtract(payedAmount);
                                if(price<=t.getAlertValue()  && price>t.getDisabValue()){
                                    result = ShipControlState.AMOUNTOUTBJ;
                                    result.message = "发货金额到达警告金额";
                                }else if(price<=t.getDisabValue()){
                                    result = ShipControlState.AMOUNTOUT;
                                    result.message = "发货金额到达控制金额";
                                }
                            }

                        }
                        case 3-> {//发货量
                            var weight = shipOrderDao.queryOrderWeight(t.getContractSN(), t.getStartTime()) + Double.valueOf(String.valueOf(netWeight));
                            if (weight > t.getAlertValue() && weight < t.getDisabValue()) {
                                result = ShipControlState.SHIPMENTOUTBJ;
                                result.message = "发货量到达警告发货量";
                            } else if (weight > t.getDisabValue()) {
                                result = ShipControlState.SHIPMENTOUT;
                                result.message = "发货量到达控制发货量";
                            }
                        }
                    }
                }
            };
            var ContractControlNoticeUserSN=HsApp.getSystemSet(CK.Contract_Control_Notice_UserSN);
            var ContractControlNoticeRoleSN=HsApp.getSystemSet(CK.Contract_Control_Notice_RoleSN);
            var ContractControlNoticeDutySN=HsApp.getSystemSet(CK.Contract_Control_Notice_DutySN);
            List<String> noticeSNList=new ArrayList<>();
            if(ContractControlNoticeUserSN!=null && !ContractControlNoticeUserSN.equals("")){
                noticeSNList.addAll(Arrays.stream(ContractControlNoticeUserSN.split(",")).toList());
            }
            if(ContractControlNoticeRoleSN!=null && !ContractControlNoticeRoleSN.equals("")){
                noticeSNList.addAll(Arrays.stream(ContractControlNoticeRoleSN.split(",")).toList());
            }
            if(ContractControlNoticeDutySN!=null && !ContractControlNoticeDutySN.equals("")){
                noticeSNList.addAll(Arrays.stream(ContractControlNoticeDutySN.split(",")).toList());
            }
            if(result==ShipControlState.SHIPMENTOUTBJ){
                for (var noticeSN : noticeSNList ) {
                    sendMsg(MsgType.System,noticeSN,"合同控制警告提醒","提醒合同编号为"+contractSN+"的合同"+result.message+"!");
                }
            }else if(result==ShipControlState.SHIPMENTOUT){
                for (var noticeSN : noticeSNList ) {
                    sendMsg(MsgType.System,noticeSN,"合同控禁止发货提醒","提醒合同编号为"+contractSN+"的合同"+result.message+"!");
                }
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Integer upDate(TransTaskEntity entity) {
        return dao.update(entity);
    }
}